#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<string.h>
#include "../include/narray.h"
#include "../include/filedesc.h"
#include "../include/vfs_errorcodes.h"
#include "../include/bst.h"
#include "../include/hash.h"




void printtre(t_node *node ,FILE *fp)
{
	if(node!=NULL)
	{
		fprintf(fp,"%s\t %s\n",node->data->file_name,node->data->path);
		printtre(node->left_child,fp);
		printtre(node->right_siblings,fp);
	}
	
	
}
void printcontents(t_node *node,FILE *fp)
{
	if(node!=NULL)
	{       
	        if(node->left_child==NULL)
	        {  
	        
	        return;
		}
		node=node->left_child;
		
		fprintf(fp,"filename:%s\t  fullpath :%s\%s\n",node->data->file_name,node->data->path,node->data->file_name);
		while(node->right_siblings!=NULL)
		{
			node=node->right_siblings;
			//fprintf(fp,"%s\n",node->data->file_name,node->data->path);
			fprintf(fp,"filename:%s\t  fullpath :%s\%s\n",node->data->file_name,node->data->path,node->data->file_name);
		}
		}
	
	
	
	
}

char* listdirc( char *path,int flag,char *p)
{	
	t_node *t2;
	char temp[300];
	if(strcmp(path,"/")==0){
		t2=root;
	}
	else
	{
		t2=search(path,&root);
		//printf("%s->the filename\n",t2->data->file_name);
	
		if(t2==NULL){
		strcpy(error,"listdir_FAILURE ");
		strcat(error,"CANNOT FIND SPECIFIED DIRECTORY");
		return error;
		}
	}	
	FILE *fp;
	fp=fopen(p,"w+");
	if(fp==NULL)
	{
			strcpy(error,"listdir_FAILURE ");
			strcat(error,ERR_VFS_LISTDIR_04 );
			return error;
	}
	else{
			
			if(flag==0)
			{
				 //~ fprintf(fp,"\n");
				if(t2->left_child!=NULL){
				//printf("yes\n");
				printcontents(t2->left_child, fp);
				
				}
				else{
				//strcpy(error,"the directory is empty\n");
				//return error;
				}
			}
			else if(flag==1)
			{
			//~ fprintf(fp,"\n");
			printcontents(t2,fp);
		}
		else{
			strcpy(error,"listdir_FAILURE ");
			strcat(error,ERR_VFS_LISTDIR_02 );
			return error;


		}
	fclose(fp);
}	
	strcpy(error,"listdir_SUCCESS ");
	return error;
}



t_node *mem_alloc()
{
	t_node * new_node;
	new_node = (t_node *)malloc(sizeof(t_node));
	return new_node;
}


int insert_node(t_node** root, fd* data)
{
	int n, i,j,count = 1,c;
	char **tokens;
	char path[MAX_PATH_SIZE];
	int counter = 0;
	int flag = 1;

	t_node * previous, *current;

	if(*root == NULL && (strcmp(data->file_name,"/") != 0) )
		return 1;

	t_node *new_node;
	new_node = mem_alloc();
	//fdno++;
                         //printf("%d is the fdno\n",fdno);
	//Insertion of the first node
	if(*root == NULL)
	{
		new_node->is_deleted = 0;
		new_node->left_child = NULL;
		new_node->right_siblings = NULL;
		new_node->parent = NULL;
		new_node->data = data;

		//Root now points to newly inserted first node "/"
		*root = new_node;
		return 0;
	}

	new_node->is_deleted = 0;
	new_node->left_child = NULL;
	new_node->right_siblings = NULL;
	new_node->parent = NULL;
	new_node->data = data;
        
	
	//Tokenizing
	strcpy(path,data->path);
	n = strlen(path);
        //printf("%s\n",path);
	if(n==1)
		count = 1;
	else
	{
	for(i=1;i<n;i++){
		if(path[i]=='/')
			count++;
	}
		count++;
	}
             
	(tokens) = (char **)malloc(sizeof(char*)*count);

	i = 0;
	for(c=0;c<count;c++)
	{
		j = 0;
		tokens[c] = (char *)malloc(sizeof(char) * 50);
		while(path[i] != '/' && path[i]!='\0')
		{
			tokens[c][j] = path[i];
			i++;
			j++;
		}
		i++;
		tokens[c][j] = '\0';
	}

	tokens[0][0] = '/';
	tokens[0][1] = '\0';
	

	
	//for(c =0; c<count; c++)
	//	printf("%s\n",tokens[c]);


	//Traverse the tree and check for the path
	i = 0;
	current = *root;
        //printf("%s\t %s\n",current->data->file_name,current->data->path);

	while(current != NULL)
	{          //printf("%s\t%s\n",current->data->file_name,tokens[i]);
		if(current->is_deleted == 0 && strcmp(current->data->file_name,tokens[i]) == 0)
		{
			i++;

			if(i == count)
                            {
                               
				break;
}
			current = current->left_child;
			
		}
		//Goto right siblings
		else if(current->right_siblings != NULL)
		{
			current = current->right_siblings;
		}
		else
		{
			flag =0;
			break;
		}
	}
     
	//Invalid positions
	if(flag == 0 || current == NULL)
	{
		return 1;
	}
	
	//Insertion of the new_node
	if(current->left_child == NULL)
	{       new_node->parent=current;
		current->left_child=new_node;
		return 0;
	}
	
	current = current->left_child;
	//previous = current;
	while(current->right_siblings != NULL)
	{       //printf("%s file name\n",current->data->file_name);
		current = current->right_siblings;
		if (strcmp(current->data->file_name,new_node->data->file_name)==0)
			return -1;
	}
        new_node->parent=current->parent;
	current->right_siblings = new_node;
        new_node->right_siblings=NULL;
        //printf("inserted %s\n",new_node->data->file_name);
	return 0;
   
}

t_node* search( char *fullpath,t_node **root)
{
	int n, i,j,count = 1,c;
	char **tokens;
	char path[MAX_PATH_SIZE];
	int flag = 1;

	t_node * previous, *current;

	t_node *new_node;
	new_node = mem_alloc();
	
	//Insertion of the first node
	if(*root == NULL)
	{
		
		return 0;
	}

	
	//Tokenizing
	strcpy(path,fullpath);
	n = strlen(path);
        //printf("%s\n",path);
	if(n==1)
		count = 1;
	else
	{
	for(i=1;i<n;i++){
		if(path[i]=='/')
			count++;
	}
		count++;
	}
             
	(tokens) = (char **)malloc(sizeof(char*)*count);

	i = 0;
	for(c=0;c<count;c++)
	{
		j = 0;
		tokens[c] = (char *)malloc(sizeof(char) * 50);
		while(path[i] != '/' && path[i]!='\0')
		{
			tokens[c][j] = path[i];
			i++;
			j++;
		}
		i++;
		tokens[c][j] = '\0';
	}

	tokens[0][0] = '/';
	tokens[0][1] = '\0';
	

	
	//for(c =0; c<count; c++)
	//	printf("%s\n",tokens[c]);


	//Traverse the tree and lcheck for the path
	i = 0;
	current = *root;
        //printf("%s\t %s\n",current->data->file_name,current->data->path);

	while(current != NULL)
	{          //printf("%s\t%s\n",current->data->file_name,tokens[i]);
		if(current->is_deleted == 0 && strcmp(current->data->file_name,tokens[i]) == 0)
		{
			i++;

			if(i == count)
				{
                 break;
				}
			current = current->left_child;
			
		}
		//Goto right siblings
		else if(current->right_siblings != NULL)
		{
			current = current->right_siblings;
		}
		else
		{
			flag =0;
			break;
		}
	}
     
	//Invalid positions
	if(flag == 0 || current == NULL)
	{
		//printf("\npath doesnot exist a new node will be inserted here\n");
		return NULL;
	}
        
	return (current);
	}




char* makedirectory(t_node **root,char *fname,char *fullpath)
{
	int n, i,j,count = 1,c;
	char **tokens;
	char path[200];
	b_node *t;
	strcpy(path,fullpath);
	t=bst_search(bst_root,path);
	//printf("%s is the ff\n",t->file_name);
	if(t!=NULL){
		strcpy(error,"makedir_FAILURE ");
	    	strcat(error,ERR_VFS_MAKEDIR_03);
	    	return error;
	    	//fprintf(fp1,"%s\n",error);
	}
	n = strlen(path);
	if(n==1)
		count = 1;
	else
	{
	for(i=1;i<n;i++){
		if(path[i]=='/')
			count++;
	}
		count++;
	}
             
	(tokens) = (char **)malloc(sizeof(char*)*count);

	i = 0;
	for(c=0;c<count;c++)
	{
		j = 0;
		tokens[c] = (char *)malloc(sizeof(char) * 50);
		while(path[i] != '/' && path[i]!='\0')
		{
			tokens[c][j] = path[i];
			i++;
			j++;
		}
		i++;
		tokens[c][j] = '\0';
	}

	tokens[0][0] = '/';
	tokens[0][1] = '\0';
	
	t_node *catch=NULL;
	char pathnode[MAX_PATH_SIZE];
	char prevpath[MAX_PATH_SIZE];
	c=0;
	
	do{
		if(c==0)
		{
		strcpy(pathnode,tokens[0]);
		}
		else if(c==1)
		{
		strcat(pathnode,tokens[c]);
		strcpy(prevpath,tokens[c-1]);
		}
		else if(c==2)
		{
		strcat(strcat(pathnode,"/"),tokens[c]);
		strcat(prevpath,tokens[c-1]);
		}
		else
		{
		strcat(strcat(pathnode,"/"),tokens[c]);
		strcat(strcat(prevpath,"/"),tokens[c-1]);
		}
		catch=search(pathnode,root);
		c++;
		}while(catch!=NULL &&  c<count);
		int flag=0;
		for(i=c;i<=count;i++)
		{
			fd *desc=(fd *)calloc(1,sizeof(fd));
			if(i>1)
			{
				if(i==2)
					{
						strcpy(prevpath,"/");
						strcpy(desc->path,prevpath);
						//flag=1
					}
				else if(i==3)
					{
						//if(flag)
						strcpy(desc->path,prevpath);
					}
				else if(i>3)
					{
						strcpy(desc->path,prevpath);
						strcat(strcat(prevpath,"/"),tokens[i-1]);
					}
				
	
			}
			else if(i==1){				
				strcpy(desc->path,"/");			
				}
			strcpy(desc->file_name,tokens[i-1]);
		if(fdno>=maxfd)
        	{
        	
        	strcpy(error,"makedir_FAILURE ");
                strcat(error,ERR_VFS_MAKEDIR_01);
                
                return error;
                }
                	 desc->is_dir=1;
                	// printf("%s\t%s\n",desc->file_name,desc->path);			
			 int k=insert_node(root,desc);	
                         fdno++;
                         //printf("%d is fdno\n",fdno);
			 int l=insert_into_list(desc->file_name,desc->path);
		
		/******IN the function given below insert ur bst ro*/
			// printf("%s\n",deesc->file_name);
		 int m=bst_insert ( &bst_root,desc );
		//	 printf("status");
		//	 printf("%d %d %d"k,l,m)
                      //int h=hash(fname);
                        //insert_into_list(h,fname,fpath);        
			 if(i==2)
			 {
				 char a[20];
				 strcpy(a,"/");
				strcat(prevpath,tokens[1]);	
			}
			else if(i==3)
			{
				char a[20];
				strcpy(a,"/");
				strcat(strcat(prevpath,"/"),tokens[2]);
			}
		}
		strcpy(error,"makedir_SUCCESS");
		return error;

}




char* deletenodes(t_node **root,char *fullpath)
{	
	char bstpath[300];
	l_node *temp1;
	b_node *t = bst_search(bst_root,fullpath);
        //printf("%s\t%s\n",t->file_desc->path,t->file_desc->file_name);
        if(t==NULL){
	strcpy(error,"deletedir_FAILURE ");
	strcat(error,ERR_VFS_DELETEDIR_01 );	
	return error;
	}
	t_node * current ,*prev=NULL;
	int flag =1;
	if (*root == NULL)
		return error;

	int n, i,j,count = 1,c;
	char **tokens;
	n = strlen(fullpath);
	if(n==1)
		count = 1;
	else
	{
		for(i=1;i<n;i++){
			if(fullpath[i]=='/')
				count++;
		}
		count++;
	}
	
	tokens= (char **)malloc(sizeof(char*)*count);

	i = 0;
	for(c=0;c<count;c++)
	{
		j = 0;
		tokens[c] = (char *)malloc(sizeof(char) * 50);
		while(fullpath[i] != '/' && fullpath[i]!='\0')
		{
			tokens[c][j] = fullpath[i];
			i++;
			j++;
		}
		i++;
		tokens[c][j] = '\0';
	}

	tokens[0][0] = '/';
	tokens[0][1] = '\0';

	i = 0;
	current = *root;
          	
	while(current != NULL)
	{       //printf("the data %s\t%s\n",current->data->file_name,tokens[i]);
		if(current->is_deleted == 0&& strcmp(current->data->file_name,tokens[i]) == 0)
		{
			i++;
			if(i == count)
				break;
				prev=current;
			current = current->left_child;
		}
		//Goto right siblings
		else if(current->right_siblings != NULL)
		{
			prev=current;
			current = current->right_siblings;
		}
		else
		{
			flag =0;
			break;
		}
	}

	//Invalid positions
	if(flag == 0 || current == NULL)
	{
	 	strcpy(error,"deletedir_FAILURE  ");
		strcat(error,ERR_VFS_DELETEDIR_01);
		return error;	
	}

	current->is_deleted = 1;
	
        strcpy(bstpath,current->data->path);
	//current->is_deleted = 1;
        if(strcmp(current->data->path,"/")==0)
	{

		strcat(bstpath,current->data->file_name);    
	}
	else{

	strcat(bstpath,"/");
	strcat(bstpath,current->data->file_name);    

	}

	bst_delete(&bst_root,bstpath);
	deletion(current->data->file_name,current->data->path);
	if(current->left_child!=NULL)
	{
		strcpy(error,"deletedir_FAILURE ");
		strcat(error,ERR_VFS_DELETEDIR_02);

                return error;	
           }
        else
	{
		prev->right_siblings=current->right_siblings;
		current->right_siblings=NULL;
		free(current);
	}
	
	//current->is_deleted = 1;
	strcpy(error,"deletedir_SUCCESS");
	return error;
}


int delete(t_node *temp){
	
       if(temp==NULL)
           return 0;
       else
        {  
         delete(temp->left_child);
   	}
return 1;
}

void deltree(fd *node)
{
	deletion(node->file_name,node->path);
        return ;
}

void del_bst(t_node *node)
{      // printf("%s\n",node->data->file_name);
	if(node!=NULL)
	{
	//node=node->left_child;
	//printf("%s left child\n",node->data->file_name);
	del_bst(node->left_child);
	char a[200];
	strcpy(a,node->data->path);
	if(strcmp(a,"/")==0)
		bst_delete(&bst_root,node->data->file_name);
	else
	{
		strcat(strcat(a,"/"),node->data->file_name);
		bst_delete(&bst_root,a);
	}
	del_bst(node->right_siblings);
	}
	return ;
}
		
		
void inserttree(fd *node)
{
	insert_into_list(node->file_name,node->path);
	bst_insert(&bst_root,node);
	return ;
}

char* movdir(char *src,char *dst,t_node **root)
{       //b_node *b=bst_search(&root,src);
        t_node *t1=search(src,&root);
	t_node *t2=search(dst,&root);
	t_node *t4=NULL;
	t_node *t5=NULL;
	t_node *t6=NULL;
	//printf("%s\t%s\n",t1->data->path,t1->data->file_name);
	//printf("%s\t%s\n",t2->data->path,t2->data->file_name);
	
        //printf("hello\n");
	char pat[200],fname[200];
	//printf("%s\t%s\n",t1-?pat,fname);
	
	//

	if(t1==NULL){
		
	 	strcpy(error,"movedir_FAILURE ");
	        strcat(error,ERR_VFS_MOVEDIR_01);
	        return error;
	
	}
	if(t2==NULL){
	 	strcpy(error,"movedir_FAILURE ");
	        strcat(error,ERR_VFS_MOVEDIR_02);
	        return error;
	
	}
	if(t1->parent==t2)
	{
		strcpy(error,"movedir_FAILURE ");
	        strcat(error,"source already in destination");
	        return error;
		}
	
	if(t1->data->is_dir==0){
		strcpy(error,"movedir_FAILURE ");
	        strcat(error,ERR_VFS_MOVEDIR_04);
	        return error;
	
	}
	if(t2->data->is_dir==0){
		strcpy(error,"movedir_FAILURE ");
	        strcat(error,ERR_VFS_MOVEDIR_07);
	        return error;
	
	}
	strcpy(pat,t1->data->path);
	strcpy(fname,t1->data->file_name);
	if(t1!=NULL && t2!=NULL)
	{
		t5=t1->parent;
		if(t5->left_child==t1)
		{
			t5->left_child=t1->right_siblings;
			t1->right_siblings=NULL;
		}
		else
		{
			t6=t5->left_child;
			while(t6->right_siblings!=t1)
			{
				t6=t6->right_siblings;
			}
			t6->right_siblings=t1->right_siblings;
			t1->right_siblings=NULL;
		}
		t4=retchild(&t2);	
		if(t4==NULL)
		{
			t2->left_child=t1;
			t1->parent=t2;
			char c[100];
			//deltree(t1->data);
			if(strcmp(t2->data->path,"/")==0)
			{
				strcpy(c,"/");
				strcat(c,t2->data->file_name);
				strcpy(t1->data->path,c);
			}
			else
			{
				
				strcpy(c,t2->data->path);
				strcat(strcat(c,"/"),t2->data->file_name);
				strcpy(t1->data->path,c);
			}
			//inserttree(t1->data);
		}
		else
		{
			//deltree(t1->data);
			t4->right_siblings=t1;
			t1->parent=t4->parent;
			strcpy(t1->data->path,t4->data->path);
			//inserttree(t1->data);
		}
		del_bst(t1->left_child);
		
		char a[200],b[200];
		strcpy(a,pat);
		if(strcmp(a,"/")==0)
		bst_delete(&bst_root,fname);
		else
		{
			int i=0;
			strcpy(b,"\0");
			strcpy(b,a);
			strcat(strcat(b,"/"),fname);
			bst_delete(&bst_root,b);
		}
		inserttree(t1->data);
		modifymove(&t1);
		strcpy(error,"movedir_SUCCESS");
		return error;
	}
	
			
}			

void modifymove(t_node **root)
{
	t_node *cnode=*root,*node=*root;
	if(root!=NULL)
	{
		if(cnode->left_child!=NULL)
		{
			node=cnode;
			cnode=cnode->left_child;
			deltree(cnode->data);
			cnode->parent=node;
			char a[100];
			if(strcmp(node->data->path,"/")==0)
			{
				strcpy(a,node->data->path);
				strcpy(cnode->data->path,strcat(a,cnode->parent->data->file_name));
			}
			else
			{
			strcpy(a,node->data->path);
			strcpy(cnode->data->path,strcat(strcat(a,"/"),cnode->parent->data->file_name));
			}
			inserttree(cnode->data);
			modifymove(&cnode);
		}
		
			while(cnode->right_siblings!=NULL)
			{
				node=cnode;
				cnode=cnode->right_siblings;
				deltree(cnode->data);
				cnode->parent=node->parent;
				char a[100];
				strcpy(a,node->data->path);
				strcpy(cnode->data->path,node->data->path);
				inserttree(cnode->data);
				modifymove(&cnode);
			}
	}
	return;
} 

t_node* retchild(t_node **node)
{
	t_node *a=*node;
	if(a->left_child==NULL)
	return NULL;
	
	else{
		a=a->left_child;
		while(a->right_siblings!=NULL)
		{
			a=a->right_siblings;
		}
		return(a);
		}	
}



